package com.ruoyi.management.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.management.base.config.AmmeterMessageConstants;
import com.ruoyi.management.base.utils.Crc16Utils;
import com.ruoyi.management.base.utils.DateUtils;
import com.ruoyi.management.base.utils.HexUtils;
import com.ruoyi.management.dao.mapper.AmmeterMapper;
import com.ruoyi.management.dao.mapper.BillingMapper;
import com.ruoyi.management.dao.mapper.WxMapper;
import com.ruoyi.management.mqtt.MqttProducer;
import com.ruoyi.management.pojo.entity.*;
import com.ruoyi.management.pojo.param.AmmeterParam;
import com.ruoyi.management.pojo.param.WXLogin;
import com.ruoyi.management.pojo.param.ZtParam;
import com.ruoyi.management.pojo.po.AmmeterResultPo;
import com.ruoyi.management.pojo.vo.*;
import com.ruoyi.management.service.AmmeterService;
import com.ruoyi.management.service.TemplateService;
import com.ruoyi.management.service.WxService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request; // 正确导入 okhttp3.Request
import okhttp3.Response; // 添加用于接收响应
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.dysmsapi20170525.Client;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Slf4j
@RequestMapping("/wx")
@RestController
@Api(tags = "小程序管理接口")
public class WxController {

    @Autowired
    private WxService wxService;
    @Autowired
    private WxMapper wxMapper;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private TemplateController templateController;
    @Autowired
    private TemplateService templateService;
    @Autowired
    private BillingMapper billingMapper;
    @Autowired
    private MqttProducer mqttProducer;
    @Autowired
    private AmmeterMapper ammeterMapper;

    // 每次批量拉取OpenID的最大数量（微信限制）
    private static final int OPENID_BATCH_LIMIT = 10000;

    // 每次批量获取用户信息的最大数量（微信限制）
    private static final int USER_INFO_BATCH_LIMIT = 100;

    // 公众号配置信息
    private static final String APPID = "wxf7e6d9100287fbee";
    private static final String APPSECRET = "ab3f6bc69123f6f0656ff1755a64d5ef";

    @Anonymous
    @ApiOperation(value = "小程序登录")
    @PostMapping("/user/login")
    public AjaxResult login(@RequestBody WXLogin wxLogin) throws IOException {
        log.info("小程序登录");
        if (wxLogin.getPhone() == null || wxLogin.getPhone().isEmpty() || wxLogin.getPassword() == null || wxLogin.getPassword().isEmpty()) {
            return AjaxResult.error("用户或密码错误");
        }
        WXloginVO wXloginVO = wxMapper.selectUserByPhone(wxLogin.getPhone());
        if (wXloginVO == null) {
            return AjaxResult.error("用户或密码错误");
        }
        if (wxLogin.getPassword().equals(wXloginVO.getPassword())) {
            //AppID
            String appId = "wx0677f4eedc55acc8";
            //密钥
            String secret = "5e7f6fa12f8e1b48cee87acc35ac4554";
            //code
            String code = wxLogin.getCode();
            String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId
                    + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code";
            //客户端
            OkHttpClient client = new OkHttpClient();
            //用url发起请求
            Request request = new Request.Builder().url(url).build();
            //拿到响应
            Response response = client.newCall(request).execute();
            //如果响应成功，打印返回值
            if (response.isSuccessful()) {
                String body = response.body().string();
                JSONObject jsonObject = JSON.parseObject(body);
                String openId = jsonObject.getString("openid");
                String unionId = jsonObject.getString("unionid");
                wXloginVO.setOpenId(openId);
                wXloginVO.setUnionId(unionId);
                int a = wxMapper.updateOpenId(wXloginVO);
                if (a <= 0) {
                    return AjaxResult.success("登录失败");
                }
            }
            // 创建 SysUser 对象（RuoYi 默认用户实体）
            SysUser sysUser = new SysUser();
            sysUser.setUserName(wXloginVO.getSj()); // 手机号作为用户名
            sysUser.setPassword(wXloginVO.getPassword());
            sysUser.setNickName(wXloginVO.getXm()); // 姓名作为昵称
            sysUser.setStatus("1");
            // 构造 LoginUser
            // 或者方式二：使用 HashSet（如果需要动态修改）
            LoginUser loginUser = new LoginUser(sysUser, new HashSet<>(Arrays.asList("user"))); // 可选角色/权限

            String token = tokenService.createToken(loginUser);

            ZTVO ztvo = wxMapper.selectZt(wXloginVO.getZt());

            BigDecimal csyje = wxMapper.selectCsyje(wXloginVO.getKhbh());

            BigDecimal kcyje = wxMapper.selectKcyje(wXloginVO.getKhbh());
            try {
                // 直接调用 TemplateController 的 getWxTemplate 方法
                String accessToken = templateController.getWxTemplate();
            } catch (Exception e) {
            }
            String gzhOpenid = wxMapper.getGzhOpenid(wXloginVO.getSj());
            if (gzhOpenid == null || gzhOpenid.isEmpty()) {
                return AjaxResult.openID("匹配公众号openid失败")
                        .put("token", token)
                        .put("user", wXloginVO)
                        .put("载体信息", ztvo)
                        .put("电表电费/容量费余额", csyje)
                        .put("空调费", kcyje);
            } else {
                // 4. 返回结果
                return AjaxResult.success()
                        .put("token", token)
                        .put("user", wXloginVO)
                        .put("载体信息", ztvo)
                        .put("电表电费/容量费余额", csyje)
                        .put("空调费", kcyje);

            }
        }
        return AjaxResult.error("用户或密码错误");
    }

    @Anonymous
    @ApiOperation(value = "小程序登录(员工版)")
    @PostMapping("/employee/login")
    public AjaxResult loginEmployee(@RequestBody WXLogin wxLogin) throws IOException {
        log.info("小程序登录(员工版)");
        if (wxLogin.getUsername() == null || wxLogin.getUsername().isEmpty() || wxLogin.getPassword() == null || wxLogin.getPassword().isEmpty()) {
            return AjaxResult.error("用户或密码错误");
        }
        WebAdmin webAdmin = wxMapper.selectloginEmployee(wxLogin.getUsername());
        if (webAdmin == null) {
            return AjaxResult.error("用户或密码错误");
        }
        if (wxLogin.getPassword().equals(webAdmin.getPassword())) {
            //AppID
            String appId = "wx0677f4eedc55acc8";
            //密钥
            String secret = "5e7f6fa12f8e1b48cee87acc35ac4554";
            //code
            String code = wxLogin.getCode();
            String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId
                    + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code";
            //客户端
            OkHttpClient client = new OkHttpClient();
            //用url发起请求
            Request request = new Request.Builder().url(url).build();
            //拿到响应
            Response response = client.newCall(request).execute();
            //如果响应成功，打印返回值
            if (response.isSuccessful()) {
                String body = response.body().string();
                JSONObject jsonObject = JSON.parseObject(body);
                String openId = jsonObject.getString("openid");
                String unionId = jsonObject.getString("unionid");
                webAdmin.setOpenId(openId);
                webAdmin.setUnionId(unionId);
                int a = wxMapper.updateOpenIdwebAdmin(webAdmin);
                if (a <= 0) {
                    return AjaxResult.success("登录失败");
                }
            }
            // 创建 SysUser 对象（RuoYi 默认用户实体）
            SysUser sysUser = new SysUser();
            sysUser.setUserName(webAdmin.getUsername()); // 昵称作为用户名
            sysUser.setPassword(webAdmin.getPassword());
            sysUser.setNickName(webAdmin.getJname()); // 姓名作为昵称
            sysUser.setStatus("1");
            // 构造 LoginUser
            // 或者方式二：使用 HashSet（如果需要动态修改）
            LoginUser loginUser = new LoginUser(sysUser, new HashSet<>(Arrays.asList("user"))); // 可选角色/权限

            String token = tokenService.createToken(loginUser);

            ZTVO ztvo = wxMapper.selectZt(webAdmin.getBm());
            try {
                // 直接调用 TemplateController 的 getWxTemplate 方法
                String accessToken = templateController.getWxTemplate();
            } catch (Exception e) {
            }
            String gzhOpenid = wxMapper.getGzhOpenidemployee(webAdmin.getId());
            if (gzhOpenid == null || gzhOpenid.isEmpty()) {
                return AjaxResult.openID("匹配公众号openid失败")
                        .put("token", token)
                        .put("员工信息", webAdmin)
                        .put("载体信息", ztvo);
            } else {
                // 4. 返回结果
                return AjaxResult.success()
                        .put("token", token)
                        .put("员工信息", webAdmin)
                        .put("载体信息", ztvo);
            }
        }
        return AjaxResult.error("用户或密码错误");
    }


    @ApiOperation(value = "修改密码")
    @PostMapping("/user/change-password")
    public AjaxResult changePassword(@RequestBody WXLogin wxLogin) {
        System.out.println(wxLogin);
        if (wxLogin.getNewpassword().equals(wxLogin.getPassword())) {
            return AjaxResult.success("新密码不能与旧密码相同");
        }
        Boolean a = wxService.changePassword(wxLogin);
        if (a) {
            return AjaxResult.success("修改成功");
        }
        return AjaxResult.success("修改失败");
    }

    @ApiOperation(value = "租户关联电表")
    @GetMapping("/ammeter")
    public AjaxResult selectusergl(
            @RequestParam("khbh") String khbh
    ) {
        log.info("租户关联电表");
        List<BillingVO> billingVOList = wxService.selectusergl(khbh);
        return AjaxResult.success(billingVOList);
    }

    @ApiOperation(value = "租户关联信息汇总简表")
    @GetMapping("/tenant_home")
    public AjaxResult tenant_home(
            @RequestParam("khbh") String khbh
    ) {
        log.info("租户关联信息汇总简表");
        TenantHomeVO tenantHomeVOS = wxService.selectTenantHome(khbh);
        return AjaxResult.success(tenantHomeVOS);
    }

    /**
     * 租户实时电量
     */
    @ApiOperation(value = "租户实时电量")
    @GetMapping("/user/realtime-power")
    public AjaxResult monthlyPowerUsage(@RequestParam("khbh") String khbh) {
        return AjaxResult.success(wxService.selectAmmeterResult(khbh));
    }

    @ApiOperation(value = "租户月度电量")
    @GetMapping("/user/monthly-power-usage")
    public AjaxResult monthlyPowerUsaged(
            @RequestParam("khbh") String khbh,
            @RequestParam("month") String month
    ) {
        log.info("租户月度电量");
        return AjaxResult.success(wxService.monthlyPowerUsage1(khbh, month));
    }


    @ApiOperation(value = "租户年度电量")
    @GetMapping("/user/yearly-power-usage")
    public AjaxResult yearlyPowerUsage(
            @RequestParam("khbh") String khbh,
            @RequestParam("year") String year
    ) {
        log.info("租户年度电量");
        return AjaxResult.success(wxService.yearlyPowerUsage(khbh, year));
    }

    @ApiOperation(value = "租户账单列表")
    @GetMapping("/user/tenant-bills")
    public AjaxResult tenantBills(
            @RequestParam(name = "khbh", required = false) String khbh,
            @RequestParam(name = "hkzt", required = false) String hkzt,
            @RequestParam("pageNum") Integer pageNum,
            @RequestParam("pageSize") Integer pageSize
    ) {
        log.info("租户账单列表");
        PageHelper.startPage(pageNum, pageSize);
        List<Qldbykhmx> qldbykhmxes = wxMapper.selectBilling(khbh, hkzt);
        PageInfo<Qldbykhmx> list = new PageInfo<>(qldbykhmxes);
        return AjaxResult.success(list);
    }


    @ApiOperation(value = "租户账单详情接口")
    @GetMapping("/user/tenant-bill")
    public AjaxResult tenantBills(
            @RequestParam(name = "khbh", required = false) String khbh,
            @RequestParam("month") String month
    ) {
        log.info("租户账单列表");
        Date date = DateUtils.getFirstDayOfMonth(month);

        List<QldbydbmxVO> qldbydbmxVOList = wxMapper.selectdbBillings(khbh, date);
        String allFjh = qldbydbmxVOList.stream()
                .map(QldbydbmxVO::getFjh) // 获取每个对象的 fjh
                .filter(fjh -> fjh != null && !fjh.isEmpty()) // 过滤空值
                .reduce((a, b) -> a + "," + b) // 拼接
                .orElse("");
        Qldbykhmx qldbykhmxes = wxMapper.selectBillings(khbh, date);
        qldbykhmxes.setFjh(allFjh);
        QldbqyinfoVO qldbqyinfoVO = wxMapper.selectQldbqyinfo(khbh);
        ZTVO ztvo = wxMapper.selectZt(qldbqyinfoVO.getZt());
        AjaxResult ajax = AjaxResult.success();
        ajax.put("电表账单", qldbydbmxVOList);
        ajax.put("租户账单", qldbykhmxes);
        ajax.put("租户信息", qldbqyinfoVO);
        ajax.put("载体信息", ztvo);
        return ajax;
    }

    @ApiOperation(value = "后付费导航/电费显示(暂无待缴费)")
    @GetMapping("/billing/powerShow")
    public AjaxResult powerShow(
            @RequestParam("khbh") String khbh
    ) {
        log.info("后付费导航/电费显示");
        List<DbkhhsjbVO> dbkhhsjbVOS = wxService.selectDbkhhsjb(khbh);
        if (dbkhhsjbVOS == null || dbkhhsjbVOS.isEmpty()) {
            return AjaxResult.success("没有客户信息");
        }
        return AjaxResult.success(dbkhhsjbVOS);
    }

    @ApiOperation(value = "是否收取滞纳金")
    @GetMapping("/billing/payment")
    public AjaxResult payment(
            @RequestParam("khbh") String khbh,
            @RequestParam("pageNum") Integer pageNum,
            @RequestParam("pageSize") Integer pageSize
    ) {
        log.info("是否收取滞纳金");
        PageHelper.startPage(pageNum, pageSize);
        List<Qldbykhmxa> qldbykhmxes = wxService.payment(khbh);
        if (qldbykhmxes == null || qldbykhmxes.isEmpty()) {
            return AjaxResult.success("没有信息");
        }
        PageInfo<Qldbykhmxa> list = new PageInfo<>(qldbykhmxes);
        return AjaxResult.success(list);
    }

    @ApiOperation(value = "缴费记录")
    @GetMapping("/billing/paymentRecord")
    public AjaxResult paymentRecord(
            @RequestParam("khbh") String khbh
    ) {
        log.info("缴费记录");
        Qldbyczmx qldbyczmx = wxService.paymentRecord(khbh);
        if (qldbyczmx == null) {
            return AjaxResult.success("没有缴费记录");
        }
        return AjaxResult.success(qldbyczmx);
    }

    @ApiOperation(value = "后付费指标块")
    @GetMapping("/postpaid")
    public AjaxResult postpaid(
            @RequestParam("khbh") String khbh,
            @RequestParam("month") String month
    ) {
        log.info("后付费指标块");
        Dbysdbb dbysdbb = wxService.postpaid(khbh, month);
        if (dbysdbb == null) {
            return AjaxResult.success("没有数据");
        }
        return AjaxResult.success(dbysdbb);
    }

    @ApiOperation(value = "预充值指标块")
    @GetMapping("/prepaid")
    public AjaxResult prepaid(
            @RequestParam("khbh") String khbh,
            @RequestParam("month") String month
    ) {
        log.info("预充值指标块");
        Dbysdbb dbysdbb = wxService.prepaid(khbh, month);
        if (dbysdbb == null) {
            return AjaxResult.success("没有数据");
        }
        return AjaxResult.success(dbysdbb);
    }

    @ApiOperation(value = "开票数据指标块")
    @GetMapping("/invoice")
    public AjaxResult invoice(
            @RequestParam("khbh") String khbh
    ) {
        log.info("开票数据指标块");
        DbkhhsjbVO dbkhhsjbVO = wxService.invoice(khbh);
        if (dbkhhsjbVO == null) {
            return AjaxResult.success("没有数据");
        }
        return AjaxResult.success(dbkhhsjbVO);
    }

    @ApiOperation(value = "显示所有已收款但未开票")
    @GetMapping("/invoiceShow")
    public AjaxResult invoiceShow(
            @RequestParam("khbh") String khbh,
            @RequestParam("year") Integer year
    ) {
        log.info("显示所有已收款但未开票");
        List<QldbysjmxVO> qldbysjmxVOS = wxService.invoiceShow(khbh, year);
        if (qldbysjmxVOS == null || qldbysjmxVOS.isEmpty()) {
            return AjaxResult.success("没有相关数据");
        }
        return AjaxResult.success(qldbysjmxVOS);
    }

    @ApiOperation(value = "开票记录")
    @GetMapping("/invoiceRecord")
    public AjaxResult invoiceRecord(
            @RequestParam("khbh") String khbh
    ) {
        log.info("开票记录");
        Qldbykp qldbykp = wxService.selectInvoiceRecord(khbh);
        if (qldbykp == null) {
            return AjaxResult.success("没有相关开票记录");
        }
        return AjaxResult.success(qldbykp);
    }

//    @ApiOperation(value = "缴费后数据处理")
//    @PostMapping("/processing")
//    public AjaxResult processing(
//            @RequestBody List<Qldbykhmx> qldbykhmxs
//
//    ) {
//    }

    @ApiOperation("缴费后数据处理")
    @GetMapping("/payment")
    public AjaxResult payment(
            @RequestParam("hkid") String hkid,
            @RequestParam("zhkje") BigDecimal zhkje,
            @RequestParam("khbh") String khbh,
            @RequestParam("zjly") String zjly,
            @RequestParam("zt") String zt,
            @RequestParam(name = "qymc", required = false) String qymc,
            @RequestParam("sjrq")
            @DateTimeFormat(pattern = "yyyy-MM-dd") Date sjrq,
            @RequestParam("tname") String tname,
            @RequestParam(value = "remark", required = false) String remark
    ) throws Exception {
        log.info("缴费后数据处理");
        //添加qldbyczmx记录
        String fylx = "";
        Qldbyczmx q1 = new Qldbyczmx();
        q1.setZt(zt);
        q1.setKhbh(khbh);
        q1.setJflx(1);
        q1.setFylx(fylx);
        q1.setCzje(zhkje);
        q1.setCzrq(sjrq);
        q1.setYx(1);
        q1.setTname(tname);
        q1.setTimestamp(new Date());
        q1.setRemark(remark);

        if (StringUtils.isNotBlank(qymc)) {
            q1.setQymc(qymc);
        }
        else if (StringUtils.isBlank(qymc) && StringUtils.isNotBlank(khbh)) {
            QldbqyinfoVO qldbqyinfoVO = wxMapper.selectQyInfoByKhbh(khbh);
            if (ObjectUtils.isNotEmpty(qldbqyinfoVO)) {
                q1.setQymc(qldbqyinfoVO.getQymc());
            }
        }
        Boolean c = wxMapper.insertQldbyczmx(q1);
        if (!c) {
            return AjaxResult.error("添加充值记录失败");
        }
        Boolean a = wxService.payment1(hkid, zhkje, khbh, zjly, tname, sjrq, remark);
        if (!a) {
            return AjaxResult.success("保存失败");
        }
        return AjaxResult.success("保存成功");
    }

    @ApiOperation(value = "用户充值，处理欠款(电费)")
    @GetMapping("/recharge")
    public AjaxResult recharge(
            @RequestParam("zt") String zt,
            @RequestParam("qymc") String qymc,
            @RequestParam("khbh") String khbh,
            @RequestParam("fylx") String fylx,
            @RequestParam("czje") BigDecimal recharge,
            @RequestParam("tname") String tname
    ) {
        //添加qldbyczmx记录
        Boolean c = qldbyczmx(zt, qymc, khbh, recharge, tname, fylx);
        if (!c) {
            return AjaxResult.error("添加充值记录失败");
        }
        if (fylx.equals("电费")) {
            BigDecimal wfksjec = wxMapper.selectWfksjec(khbh, zt);
            if (wfksjec.compareTo(BigDecimal.ZERO) > 0) {
                //查询充值用户未付费账单
                List<Qldbykhmx> qldbykhmxs = wxMapper.prepaidRecharge(khbh, zt);
                for (Qldbykhmx qldbykhmx : qldbykhmxs) {
                    //查询账户余额
                    BigDecimal csyje = billingMapper.getcsyje(qldbykhmx.getKhbh());
                    if (csyje.compareTo(qldbykhmx.getZje()) >= 0) {// 当余额大于等于当月应交电费时执行的逻辑
                        QldbysjmxVO f1 = new QldbysjmxVO();
                        f1.setZt(qldbykhmx.getZt());
                        f1.setQymc(qldbykhmx.getQymc());
                        f1.setKhbh(qldbykhmx.getKhbh());
                        f1.setHkid(qldbykhmx.getHkid());
                        f1.setNf(qldbykhmx.getNf());
                        f1.setYf(qldbykhmx.getYf());
                        f1.setHklx(qldbykhmx.getHklx());
                        f1.setHkrq(qldbykhmx.getHkrq());
                        f1.setHkks(qldbykhmx.getHkks());
                        f1.setHkjs(qldbykhmx.getHkjs());
                        f1.setHkzt("已收款");
                        f1.setHkje(qldbykhmx.getYs());
                        f1.setYsje(qldbykhmx.getYs());
                        f1.setWsje(BigDecimal.ZERO);
                        f1.setZnysje(qldbykhmx.getZnj());
                        f1.setSjrq(new Date());
                        f1.setTname(tname);
                        f1.setTimestamp(new Date());
                        f1.setZjly("充值");
                        f1.setZjbs(1);
                        f1.setJflx(2);
                        //新增已收明细表记录qldbysjmx
                        Boolean a = billingMapper.insertQldbysjmx(f1);
                        if (!a) {
                            throw new RuntimeException("新增已收明细表记录失败");
                        }
                        Qldbykhmx q1 = new Qldbykhmx();
                        q1.setHkid(qldbykhmx.getHkid());
                        q1.setHkzt("已收款");
                        //已交电费
                        q1.setYsje(qldbykhmx.getYs());
                        //未交电费
                        q1.setWsje(BigDecimal.ZERO);
                        q1.setSjrq(new Date());
                        //更新应收表qldbykhmx
                        Boolean b = billingMapper.updateQldbykhmx(q1);
                        if (!b) {
                            throw new RuntimeException("更新应收表qldbykhmx失败");
                        }
                        BigDecimal csyje1 = wxMapper.selectCsyje(khbh);
                        System.out.println("【苏州青澜实业】尊敬的客户：您好！" + qldbykhmx.getNf() + "年" + qldbykhmx.getYf() + "月" + qldbykhmx.getHklx() + qldbykhmx.getYs() + "元已全部核销。现充值可用余额" + csyje1 + "元，点击此处查看");

                        //通知客户：上月电表电费/容量费，当前剩余可用余额
                    }
                    if (csyje.compareTo(qldbykhmx.getZje()) < 0 && csyje.compareTo(BigDecimal.ZERO) != 0) {// 当余额小于当月应交电费时并且不等于0执行的逻辑
                        QldbysjmxVO f1 = new QldbysjmxVO();
                        f1.setZt(qldbykhmx.getZt());
                        f1.setQymc(qldbykhmx.getQymc());
                        f1.setKhbh(qldbykhmx.getKhbh());
                        f1.setHkid(qldbykhmx.getHkid());
                        f1.setNf(qldbykhmx.getNf());
                        f1.setYf(qldbykhmx.getYf());
                        f1.setHklx(qldbykhmx.getHklx());
                        f1.setHkrq(qldbykhmx.getHkrq());
                        f1.setHkks(qldbykhmx.getHkks());
                        f1.setHkjs(qldbykhmx.getHkjs());
                        f1.setHkzt("已收款");

                        //当余额少于应收电费时
                        if (csyje.compareTo(qldbykhmx.getYs()) <= 0) {
                            f1.setHkje(qldbykhmx.getYs());
                            f1.setYsje(csyje);//余额大于应收，应交电费就等于已收，处理滞纳金
                            BigDecimal wsje = qldbykhmx.getYs().subtract(csyje);//未交电费计算
                            f1.setWsje(wsje);//未交电费
                            f1.setZnysje(BigDecimal.ZERO);
                            f1.setSjrq(new Date());
                            f1.setTname(tname);
                            f1.setTimestamp(new Date());
                            f1.setZjly("充值");
                            f1.setZjbs(1);
                            f1.setJflx(2);
                            //新增已收明细表记录qldbysjmx
                            Boolean a = billingMapper.insertQldbysjmx(f1);
                            if (!a) {
                                throw new RuntimeException("新增已收明细表记录失败");
                            }
                            Qldbykhmx q1 = new Qldbykhmx();
                            q1.setHkid(qldbykhmx.getHkid());
                            q1.setHkzt("部分收款");
                            //已交电费
                            q1.setYsje(csyje);
                            //未交电费
                            q1.setWsje(wsje);
                            q1.setSjrq(new Date());
                            //更新应收表qldbykhmx
                            Boolean b = billingMapper.updateQldbykhmx(q1);
                            if (!b) {
                                throw new RuntimeException("更新应收表qldbykhmx失败");
                            }
                            //通知客户：上月电表电费/容量费，当前欠费
                            System.out.println("【苏州青澜实业】尊敬的客户：您好！" + qldbykhmx.getNf() + "年" + qldbykhmx.getYf() + "月使用电量452度，" + qldbykhmx.getHklx() + qldbykhmx.getYs() + "元，已核销" + csyje + "元，可用余额<0，您已欠费，点击此处充值");
                        } else {//当余额大于应收电费时，多出来的余额就是已交滞纳金

                            f1.setHkje(qldbykhmx.getYs());
                            f1.setYsje(qldbykhmx.getYs());
                            f1.setWsje(BigDecimal.ZERO);
                            BigDecimal znj = csyje.subtract(qldbykhmx.getYs());
                            f1.setZnysje(znj);//剩余可用余额为滞纳金
                            f1.setSjrq(new Date());
                            f1.setTname(tname);
                            f1.setTimestamp(new Date());
                            f1.setZjly("充值");
                            f1.setZjbs(1);
                            f1.setJflx(2);
                            //新增已收明细表记录qldbysjmx
                            Boolean a = billingMapper.insertQldbysjmx(f1);
                            if (!a) {
                                throw new RuntimeException("新增已收明细表记录失败");
                            }
                            Qldbykhmx q1 = new Qldbykhmx();
                            q1.setHkid(qldbykhmx.getHkid());
                            q1.setHkzt("部分收款");
                            //已交电费
                            q1.setYsje(qldbykhmx.getYs());
                            //未交电费
                            q1.setWsje(BigDecimal.ZERO);
                            q1.setSjrq(new Date());
                            //更新应收表qldbykhmx
                            Boolean b = billingMapper.updateQldbykhmx(q1);
                            if (!b) {
                                throw new RuntimeException("更新应收表qldbykhmx失败");
                            }
                            //通知客户：上月电表电费/容量费，当前欠费
                            System.out.println("【苏州青澜实业】尊敬的客户：您好！" + qldbykhmx.getNf() + "年" + qldbykhmx.getYf() + "月使用电量452度，" + qldbykhmx.getHklx() + qldbykhmx.getYs() + "元，已核销" + qldbykhmx.getYs() + "元，可用余额<0，您已欠费，点击此处充值");
                        }
                    }
                    if (csyje.compareTo(BigDecimal.ZERO) == 0) {
                        log.info("账户余额为0,无法抵扣应收");
                        break;
                    }
                }
            }
            BigDecimal wfksjec1 = wxMapper.selectWfksjec(khbh, zt);
            if (wfksjec1.compareTo(BigDecimal.ZERO) == 0) {
                BigDecimal cyje = wxMapper.selectCsyje1(khbh, zt);
                //查询余额
                BigDecimal yeje = wxMapper.selectCsyje(khbh);
                //实时判断未欠费
                Date date = new Date();

                // 2. 定义目标格式：yyyy-MM-dd HH:mm:ss（与 2025-08-19 15:50:05 格式匹配）
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

                // 3. 转换逻辑：Date → Instant → LocalDateTime（绑定时区）→ 格式化字符串
                LocalDateTime localDateTime = LocalDateTime.ofInstant(
                        date.toInstant(),  // Date 转 Java 8+ 时间戳 Instant
                        ZoneId.systemDefault()  // 绑定系统时区（中国环境默认是 Asia/Shanghai，避免时区偏移）
                );

                // 4. 执行格式化
                String formattedTime = localDateTime.format(formatter);
                if (cyje.compareTo(BigDecimal.ZERO) >= 0) {
                    Integer i = wxMapper.selectAmmeterStatus(khbh, zt);
                    if (i == 1) {
                        System.out.println("发送充值提醒:【苏州青澜实业】尊敬的客户：您好！您已于" + formattedTime + "充值" + recharge + "元，可用余额" + yeje + "元。感谢您的支持！点击查看");
                    }
                    if (i == 2) {
                        List<AmmeterParam> ammeterParams = wxMapper.selectAmmeterStatuss(zt, khbh);
                        boolean allSuccess = true;
                        List<String> failedDbbhList = new ArrayList<>();
                        // 二次合闸机制：最多重试1次（共2次尝试）
                        final int MAX_RETRY_COUNT = 1; // 1次重试 = 首次+1次二次尝试

                        for (AmmeterParam ammeterParam : ammeterParams) {
                            boolean isSuccess = false;
                            // 记录当前电表的合闸结果
                            String dbbh = ammeterParam.getDbbh();

                            // 循环执行合闸（含重试）
                            for (int retry = 0; retry <= MAX_RETRY_COUNT; retry++) {
                                try {
                                    // 生成合闸指令（与原逻辑一致）
                                    byte[] crcHexString = Crc16Utils.getData(
                                            ammeterParam.getTid(),
                                            AmmeterMessageConstants.AMMETER_SWITCH_OPERATION_1,
                                            AmmeterMessageConstants.AMMETER_PUBLISH_NULL,
                                            AmmeterMessageConstants.AMMETER_SWITCH_OPERATION_2,
                                            AmmeterMessageConstants.AMMETER_SWITCH_OPERATION_4,
                                            AmmeterMessageConstants.AMMETER_SWITCH_OPERATION_4
                                    );
                                    log.debug("电表 {} 第{}次合闸 - CRC效验码: {}", dbbh, retry + 1, crcHexString);

                                    // 转换消息并发送
                                    String finalMessageHex = Crc16Utils.byteTo16String(crcHexString).toUpperCase();
                                    log.info("电表 {} 第{}次合闸 - 最终消息: {}", dbbh, retry + 1, finalMessageHex);

                                    byte[] payload = HexUtils.HexStringToByte(finalMessageHex);
                                    mqttProducer.send(ammeterParam.getPtopic(), payload);

                                    // 等待时间随重试次数增加（首次1s，二次2s，避免高频请求）
                                    Thread.sleep(1000 * (retry + 1));

                                    // 检查合闸状态
                                    Integer status = ammeterMapper.selectAmmeterStatus(dbbh);
                                    if (status == 1) {
                                        log.info("电表 {} 第{}次合闸成功", dbbh, retry + 1);
                                        isSuccess = true;
                                        break; // 成功则退出重试循环
                                    } else {
                                        log.warn("电表 {} 第{}次合闸失败，当前状态: {}", dbbh, retry + 1, status);
                                    }
                                } catch (Exception e) {
                                    log.error("电表 {} 第{}次合闸异常", dbbh, retry + 1, e);
                                    // 异常时继续重试，直到达到最大次数
                                }
                            }

                            // 所有尝试后仍失败，记录失败信息
                            if (!isSuccess) {
                                failedDbbhList.add(dbbh);
                                allSuccess = false;
                            }
                        }

                        // 处理最终结果
                        if (allSuccess) {
                            System.out.println("【苏州青澜实业】尊敬的客户：您好！您已于" + formattedTime + "充值" + recharge + "元，可用余额" + yeje + "元，已复电。点击查看");
                            System.out.println("【苏州青澜实业】客户********.... 已充值复电");
                        } else {
                            String errorMsg = "复电失败，以下电表经" + (MAX_RETRY_COUNT + 1) + "次合闸仍未成功：" + String.join(",", failedDbbhList);
                            System.out.println("【苏州青澜实业】" + errorMsg);
                            throw new RuntimeException(errorMsg);
                        }

                        // 更新企业表状态（仅在所有电表处理完成后执行）
                        Boolean updateResult = wxMapper.updateQY(khbh, zt);
                        if (!updateResult) {
                            throw new RuntimeException("更新qydbqyinfo表失败");
                        }
                    }
                } else {
                    System.out.println("发送欠费充值提醒:【苏州青澜实业】尊敬的客户：您好！您已于" + formattedTime + " 充值" + recharge + "元，当前可用余额<0。点击此处充值");
                }
            }
        }
        BigDecimal csyje = wxMapper.selectCsyje(khbh);

// 定义阈值：50元和20元
        BigDecimal threshold50 = new BigDecimal("50");
        BigDecimal threshold20 = new BigDecimal("20");

// 当余额大于等于20元且小于50元时，发送"不足50元"提醒
        if (csyje.compareTo(threshold20) >= 0 && csyje.compareTo(threshold50) < 0) {
            System.out.println("【苏州青澜实业】尊敬的客户：刚检测到您的充值可用余额已不足50元，为了不影响您正常用电，建议您尽快充值");
        }

// 当余额小于20元（且大于0，避免与欠费提醒重复）时，发送"不足20元"提醒
        if (csyje.compareTo(BigDecimal.ZERO) > 0 && csyje.compareTo(threshold20) < 0) {
            System.out.println("【苏州青澜实业】尊敬的客户：刚检测到您的充值可用余额已不足20元，为了不影响您正常用电，建议您尽快充值");
        }
        //Boolean a=wxService.recharge(khbh,recharge,tname,fylx);
        return AjaxResult.success("充值成功");
    }


    @ApiOperation(value = "预付费用户余额")
    @GetMapping("/prepaidBalance")
    public AjaxResult prepaidBalance(
            @RequestParam("khbh") String khbh
    ) {
        log.info("预付费用户余额");

        BigDecimal csyje = wxMapper.selectCsyje(khbh);

        BigDecimal kcyje = wxMapper.selectKcyje(khbh);
        return AjaxResult.success()
                .put("电费余额", csyje)
                .put("空调费余额", kcyje);
    }

    @ApiOperation(value = "缴费流水/预充值流水")
    @GetMapping("/paymentRecord")
    public AjaxResult paymentRecord2(
            @RequestParam(name = "khbh", required = false) String khbh,
            @RequestParam(name = "zt", required = false) String zt,
            @RequestParam("jflx") Integer jflx,
            @RequestParam(name = "fylx", required = false) String fylx,
            @RequestParam("month") String month,
            @RequestParam(name = "qymc", required = false) String qymc,
            @RequestParam("tgszt") String tgszt,
            @RequestParam("pageNum") Integer pageNum,
            @RequestParam("pageSize") Integer pageSize
    ) {

        // 当前账号非admin账号
        if (StringUtils.isNotBlank(tgszt) && !"1".equals(tgszt)) {
            ZtParam ztParam = new ZtParam();
            ztParam.setTgszt(tgszt);
            List<ZTVO> ztvos = ammeterMapper.selectZtByNra(ztParam);
            if (CollectionUtils.isNotEmpty(ztvos)) {
                zt = ztvos.get(0).getNr();
            }
        }
        if (jflx == 1) {
            PageHelper.startPage(pageNum, pageSize);
            List<Qldbyczmx> qldbysjmxVOS = wxService.paymentRecord111(khbh, zt, jflx, month, qymc);
            if (qldbysjmxVOS == null || qldbysjmxVOS.isEmpty()) {
                return AjaxResult.success("没有数据");
            }
            PageInfo<Qldbyczmx> list = new PageInfo<>(qldbysjmxVOS);
            return AjaxResult.success(list);
        }
        if (jflx == 2) {
            PageHelper.startPage(pageNum, pageSize);
            List<Qldbyczmx> qldbyczmxs = wxService.paymentRecord2(khbh, zt, jflx, fylx, month, qymc);
            if (qldbyczmxs == null || qldbyczmxs.isEmpty()) {
                return AjaxResult.success("没有数据");
            }
            PageInfo<Qldbyczmx> list = new PageInfo<>(qldbyczmxs);
            return AjaxResult.success(list);
        }
        return AjaxResult.error("参数错误");
    }

    @ApiOperation(value = "租户每月已收明细及看板")
    @GetMapping("/tenantsjmx")
    public AjaxResult tenantysmx(
            @RequestParam(name = "khbh", required = false) String khbh,
            @RequestParam("zt") String zt
    ) {
        log.info("租户每月已收明细及看板");
        if (khbh == null) {
            List<Qldbyczmx> qldbyczmxList = wxMapper.paymentRecord2(zt);
            return AjaxResult.success(qldbyczmxList);
        }
        DbkhhsjbVO dbkhhsjbVO = wxMapper.tenantysmx(khbh, zt);
        if (dbkhhsjbVO.getJflx() == 1) {
            List<RechargeRecord> qldbysjmxVOS = wxService.tenantysmx(khbh, zt);
            if (qldbysjmxVOS == null || qldbysjmxVOS.isEmpty()) {
                return AjaxResult.success("没有数据");
            }
            return AjaxResult.success()
                    .put("应收电费", dbkhhsjbVO.getHkjeb())
                    .put("已收电费", dbkhhsjbVO.getYsjec())
                    .put("未收电费", dbkhhsjbVO.getWsjec())
                    .put("已收金额明细", qldbysjmxVOS);

        }
        if (dbkhhsjbVO.getJflx() == 2) {
            System.out.println(dbkhhsjbVO);
            List<RechargeRecord> qldbysjmxVOS = wxService.tenantysmx(khbh, zt);
            if (qldbysjmxVOS == null || qldbysjmxVOS.isEmpty()) {
                return AjaxResult.success("没有数据");
            }
            return AjaxResult.success()
                    .put("总充值金额", dbkhhsjbVO.getZczjee())
                    .put("总核销余额", dbkhhsjbVO.getYsjec().add(dbkhhsjbVO.getZnjec()))
                    .put("总可用余额", dbkhhsjbVO.getZczjee().subtract(dbkhhsjbVO.getYsjec().subtract(dbkhhsjbVO.getZnjec())))
                    .put("已收金额明细", qldbysjmxVOS);
        }
        return AjaxResult.error("缴费类型参数错误");
    }


    public Boolean qldbyczmx(String zt, String qymc, String khbh, BigDecimal recharge, String tname, String fylx) {
        //新增qldbyczmx表(修改)
        Qldbyczmx q1 = new Qldbyczmx();
        q1.setZt(zt);
        q1.setQymc(qymc);
        q1.setKhbh(khbh);
        q1.setJflx(2);
        q1.setFylx(fylx);
        q1.setCzje(recharge);
        q1.setCzrq(new Date());
        q1.setYx(1);
        q1.setTname(tname);
        q1.setTimestamp(new Date());
        Boolean a = wxMapper.insertQldbyczmx(q1);
        try {
            Thread.sleep(2000);  // 线程休眠2秒
        } catch (InterruptedException e) {
            // 必须有代码块（即使为空）
        }
        return a;
    }

    @ApiOperation(value = "后付费全部账单(已核销/部分核销/应收/欠费)")
    @GetMapping("/postpaid1")
    public AjaxResult postpaid1(
            @RequestParam("khbh") String khbh,
            @RequestParam("zt") String zt,
            @RequestParam("status") Integer status,
            @RequestParam("pageNum") Integer pageNum,
            @RequestParam("pageSize") Integer pageSize
    ) {
        PageHelper.startPage(pageNum, pageSize);
        List<Qldbykhmx> qldbykhmxs = wxService.postpaid1(khbh, zt, status);
        if (qldbykhmxs == null || qldbykhmxs.isEmpty()) {
            return AjaxResult.success("没有数据");
        }
        PageInfo<Qldbykhmx> list = new PageInfo<>(qldbykhmxs);
        return AjaxResult.success(list);
    }

    @ApiOperation(value = "后付费租户显示")
    @GetMapping("/postpaidShow")
    public AjaxResult postpaidShow(
            @RequestParam(name = "qymc", required = false) String qymc,
            @RequestParam("bm") String bm,
            @RequestParam("dbqx") Integer dbqx,
            @RequestParam("pageNum") Integer pageNum,
            @RequestParam("pageSize") Integer pageSize
    ) {
        PageHelper.startPage(pageNum, pageSize);
        List<DbkhhsjbVO> qldbykhmxs = wxService.postpaidShow(qymc, bm, dbqx);
        if (qldbykhmxs == null || qldbykhmxs.isEmpty()) {
            return AjaxResult.success("没有数据");
        }
        PageInfo<DbkhhsjbVO> list = new PageInfo<>(qldbykhmxs);
        return AjaxResult.success(list);
    }

    @ApiOperation(value = "停电列表显示")
    @GetMapping("/powerOffShow")
    public AjaxResult powerOffShow(
            @RequestParam("zt") String zt,
            @RequestParam(name = "qymc", required = false) String qymc,
            @RequestParam("pageNum") Integer pageNum,
            @RequestParam("pageSize") Integer pageSize
    ) {
        PageHelper.startPage(pageNum, pageSize);
        List<Dbysdba1t> dbysdba1ts = wxMapper.powerOffShow(zt, qymc);
        if (dbysdba1ts == null || dbysdba1ts.isEmpty()) {
            return AjaxResult.success("没有数据");
        }
        PageInfo<Dbysdba1t> list = new PageInfo<>(dbysdba1ts);
        return AjaxResult.success(list);
    }

    @ApiOperation(value = "欠费停电通知")
    @GetMapping("/powerOffNotice")
    public AjaxResult powerOffNotice(
            @RequestParam("zt") String zt,
            @RequestParam("khbh") String khbh
    ) throws Exception {
        List<Dbysdba1t> dbysdba1ts = wxMapper.powerOffNotice(zt, khbh);
        if (dbysdba1ts != null || dbysdba1ts.isEmpty()) {
            for (Dbysdba1t t1 : dbysdba1ts) {
                Config config = new Config()
                        // 替换为你的 AccessKey ID
                        .setAccessKeyId("LTAI5tREYeNL71j7RfygWnHk")
                        // 替换为你的 AccessKey Secret
                        .setAccessKeySecret("rlNi5pJPYQVdo7cT7kzn7k0UeMmSNK");
                // 阿里云短信服务的 endpoint
                config.endpoint = "dysmsapi.aliyuncs.com";
                Client client = new Client(config);
                // 构造API请求对象，请替换请求参数值
                SendSmsRequest sendSmsRequest = new SendSmsRequest()
                        .setPhoneNumbers(t1.getSj())
                        .setSignName("苏州青澜实业")  // 注意：这里的签名名称必须是在阿里云控制台已审核通过的
                        .setTemplateCode("SMS_493800185"); // 模板CODE必须是已审核通过的
                // 获取响应对象
                SendSmsResponse sendSmsResponse = client.sendSms(sendSmsRequest);
                // 响应包含服务端响应的 body 和 headers
                System.out.println(com.aliyun.teautil.Common.toJSONString(sendSmsResponse));
            }
        }
        return AjaxResult.success("操作成功");
    }

    @ApiOperation(value = "租户每月已收明细及看板")
    @GetMapping("/monthpaymentRecord")
    public AjaxResult monthpaymentRecord(
            @RequestParam("khbh") String khbh,
            @RequestParam("zt") String zt,
            @RequestParam("month") String month,
            @RequestParam(name = "jflx", required = false) String jflx
    ) {
        Date date = DateUtils.getFirstDayOfMonth(month);
        BigDecimal zje = wxMapper.monthpaymentRecordSum(khbh, zt, date);
        List<QldbysjmxVO> qldbysjmxVOS = wxMapper.monthpaymentRecord(khbh, zt, date);
        return AjaxResult.success(qldbysjmxVOS)
                .put("当月已收金额", zje);

    }

    @ApiOperation(value = "租户每月已收金额（微信）")
    @GetMapping("/monthpaymentRecordwx")
    public AjaxResult monthpaymentRecordwx(
            @RequestParam(name = "qymc", required = false) String qymc,
            @RequestParam("zt") String zt,
            @RequestParam("month") String month,
            @RequestParam("dbqx") Integer dbqx,
            @RequestParam("pageNum") Integer pageNum,
            @RequestParam("pageSize") Integer pageSize
    ) {
        Date date = DateUtils.getFirstDayOfMonth(month);
        PageHelper.startPage(pageNum, pageSize);
        List<QldbysjmxVO> qldbysjmxVOS = wxService.wxmonth(qymc, zt, date, dbqx);
        PageInfo<QldbysjmxVO> list = new PageInfo<>(qldbysjmxVOS);
        return AjaxResult.success(list);
    }


}
